package ru.batrdmi.svnplugin.actions;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.DiffManager;
import com.intellij.openapi.diff.DiffRequest;
import com.intellij.openapi.diff.SimpleContent;
import com.intellij.openapi.diff.SimpleDiffRequest;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vcs.FilePath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNPropertyValue;
import ru.batrdmi.svnplugin.SVNRevisionGraph;
import ru.batrdmi.svnplugin.logic.FileHistoryRetriever;
import ru.batrdmi.svnplugin.logic.Revision;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class ShowPropertiesDiffAction extends AnAction {
    private static final Logger log = Logger.getInstance("ru.batrdmi.svnplugin.actions.ShowPropertiesDiffAction");

    public ShowPropertiesDiffAction() {
        super("Compare properties with local", "Compare properties with local version",
                IconLoader.getIcon("/icons/PropertiesDiff.png"));
    }

    @Override
    public void update(AnActionEvent e) {
        List<Revision> selection = e.getData(SVNRevisionGraph.SELECTED_REVISIONS);
        int selectionSize = (selection == null) ? 0 : selection.size();
        Presentation p = e.getPresentation();
        if (selectionSize == 1) {
            p.setText("Compare properties with local");
            p.setDescription("Compare properties with local version");
        } else {
            p.setText("Compare properties");
            p.setDescription("Compare properties");
        }
        boolean enabled = (selectionSize == 1 && !selection.get(0).isDeleted())
                    || (selectionSize == 2 && !selection.get(0).isDeleted() && !selection.get(1).isDeleted());
        p.setEnabled(enabled);
        if (ActionPlaces.isPopupPlace(e.getPlace())) {
            p.setVisible(enabled);
        }
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        final Project project = e.getData(PlatformDataKeys.PROJECT);
        SvnVcs svn = SvnVcs.getInstance(project);
        FilePath filePath = e.getData(SVNRevisionGraph.SRC_FILE);
        if (filePath == null) {
            return;
        }
        List<Revision> revisions = e.getData(SVNRevisionGraph.SELECTED_REVISIONS);
        int selectionSize = (revisions == null) ? 0 : revisions.size();
        final Revision[] revs = new Revision[2];
        if (selectionSize == 2) {
            revs[0] = revisions.get(0);
            revs[1] = revisions.get(1);
        } else if (selectionSize == 1) {
            revs[0] = revisions.get(0);
            revs[1] = e.getData(SVNRevisionGraph.CURRENT_REVISION);
        } else {
            return;
        }
        Arrays.sort(revs, new Revision.RevisionNumberComparator());
        final FileHistoryRetriever historyRetriever = new FileHistoryRetriever(svn, filePath.getVirtualFile());
        new Task.Modal(project, "Loading properties from repository", false) {
            DiffRequest diffRequest;

            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                try {
                    indicator.setText("Loading properties for " + revs[0]);
                    SVNProperties p1 = historyRetriever.getFileProperties(revs[0]);
                    indicator.setText("Loading properties for " + revs[1]);
                    SVNProperties p2 = historyRetriever.getFileProperties(revs[1]);
                    diffRequest = createDiffRequest(project, revs[0], p1, revs[1], p2);
                } catch (SVNException e) {
                    log.error("Error retrieving properties", e);
                }
            }

            @Override
            public void onSuccess() {
                if (diffRequest == null) {
                    Messages.showErrorDialog(project, "Error retrieving properties from repository",
                            SVNRevisionGraphAction.ERROR_DIALOG_TITLE);
                } else {
                    DiffManager.getInstance().getDiffTool().show(diffRequest);
                }
            }
        }.queue();
    }

    private DiffRequest createDiffRequest(Project project, Revision r1, SVNProperties p1,
                                          Revision r2, SVNProperties p2) {
        SimpleDiffRequest request = new SimpleDiffRequest(project, "Subversion properties difference");
        request.setContentTitles(r1.toString(), r2.toString());
        request.setContents(new SimpleContent(propertiesToString(p1)),
                new SimpleContent(propertiesToString(p2)));
        return request;
    }

    @SuppressWarnings("unchecked")
    private String propertiesToString(SVNProperties props) {
        StringBuilder b = new StringBuilder();
        Map<String, SVNPropertyValue> properties = new TreeMap<String, SVNPropertyValue>(props.asMap());
        for (Map.Entry<String, SVNPropertyValue> e : properties.entrySet()) {
            b.append(e.getKey()).append('=').append(e.getValue()).append('\n');
        }
        return b.toString();
    }
}
